package net

import (
	"common/logs"
	"common/ut"
	"connector/game"
	"connector/protocol"
	"core/remote"
	"encoding/json"
	"errors"
	"fmt"
	"golang.org/x/exp/rand"
	"strings"
	"time"
)

type Event func(packet *protocol.Packet, c *WsConnection) error
type LogicHandler map[string]LogicHandlerFunc
type LogicHandlerFunc func(session *Session, body []byte) (any, error)

type EventHandler struct {
	serverId       string
	Handlers       map[protocol.PackageType]Event
	logicHandlers  LogicHandler
	client         remote.Client
	wsClients      map[string]*WsConnection
	RemoteReadChan chan []byte
	RemotePushChan chan *remote.Msg
}

// NewEventHandler client：远程通信客户端
func NewEventHandler(serverId string, wsClients map[string]*WsConnection) *EventHandler {
	handler := new(EventHandler)
	handler.serverId = serverId
	initHandler(handler)
	handler.logicHandlers = make(LogicHandler)
	handler.RemoteReadChan = make(chan []byte, MaxMessageSize)
	handler.RemotePushChan = make(chan *remote.Msg, MaxMessageSize)
	// 1. 初始化客户端连接，用于和其他服务通信
	handler.client = remote.NewNatsClient(handler.serverId, handler.RemoteReadChan)
	if err := handler.client.Run(); err != nil {
		logs.Fatal("%s", err)
	}
	handler.wsClients = wsClients
	// 2. 监听消息
	go handler.remoteReadChanHandler()
	go handler.remotePushChanHandler()
	return handler
}

// 初始化默认的 Handler
func initHandler(e *EventHandler) {
	e.Handlers = make(map[protocol.PackageType]Event, 5)
	e.Handlers[protocol.Handshake] = e.HandshakeHandler
	e.Handlers[protocol.HandshakeAck] = e.HandshakeAckHandler
	e.Handlers[protocol.Heartbeat] = e.HeartbeatHandler
	e.Handlers[protocol.Data] = e.MessageHandler
	e.Handlers[protocol.Kick] = e.KickHandler
}

// RegisterLogicHandler 注册一个 LogicHandler
func (e *EventHandler) RegisterLogicHandler(key string, handlerFunc LogicHandlerFunc) {
	e.logicHandlers[key] = handlerFunc
}

// HandshakeHandler 握手处理器
func (e *EventHandler) HandshakeHandler(packet *protocol.Packet, c *WsConnection) error {
	logs.Debug("收到客户端 [ %s ] 的握手请求：%v", c.Cid, packet)
	response := protocol.HandshakeResponse{
		Code: 200,
		Sys: protocol.Sys{
			Heartbeat: 3,
		},
	}
	data, _ := json.Marshal(response)
	// 编码发送给客户端
	buf, err := protocol.Encode(packet.Type, data)
	if err != nil {
		return err
	}
	return c.SendMessage(buf)
}

// HandshakeAckHandler ack 处理器
func (e *EventHandler) HandshakeAckHandler(packet *protocol.Packet, c *WsConnection) error {
	logs.Debug("收到客户端 [ %s ] 的 ACK 请求：%v", c.Cid, packet.Body)
	return nil
}

// HeartbeatHandler 心跳处理器
func (e *EventHandler) HeartbeatHandler(packet *protocol.Packet, c *WsConnection) error {
	logs.Debug("收到客户端 [ %s ] 的握手请求：%v", c.Cid, packet)
	var response []byte
	data, _ := json.Marshal(response)
	// 编码发送给客户端
	buf, err := protocol.Encode(packet.Type, data)
	if err != nil {
		return err
	}
	return c.SendMessage(buf)
}

// MessageHandler 数据处理器
func (e *EventHandler) MessageHandler(packet *protocol.Packet, c *WsConnection) error {
	message := packet.MessageBody()
	logs.Debug("收到客户端 [ %s ] 的消息。路由：%s，类型：%s，消息：%s", c.Cid, message.Route, message.Type, string(message.Data))
	router := strings.Split(message.Route, ".")
	if len(router) == 3 {
		// connector.entryHandler.entry
		serverType := router[0]
		// 根据 handlerMethod 调用不同的逻辑处理器
		handlerMethod := fmt.Sprintf("%s.%s", router[1], router[2])
		connectorConfig := game.Conf.GetConnectorByServerType(serverType)
		if connectorConfig != nil {
			// 本地 connector 服务器
			h, ok := e.logicHandlers[handlerMethod]
			if ok {
				data, err := h(c.Session, message.Data)
				if err != nil {
					return err
				}
				// 将消息打包并发送
				marshal, _ := json.Marshal(data)
				message.Type = protocol.Response
				message.Data = marshal
				encode, err := protocol.MessageEncode(message)
				if err != nil {
					return err
				}
				response, err := protocol.Encode(packet.Type, encode)
				if err != nil {
					return err
				}
				return c.SendMessage(response)
			}
		} else {
			dst, err := e.selectDst(serverType)
			if err != nil {
				logs.Error("选择服务节点异常：%v", err)
				return err
			}
			msg := &remote.Msg{
				Cid:         c.Cid,
				Uid:         c.Session.Uid,
				Src:         e.serverId,
				Dst:         dst,
				Router:      handlerMethod,
				Body:        message,
				SessionData: c.Session.data,
			}
			marshal, _ := json.Marshal(msg)
			if err := e.client.SendMsg(dst, marshal); err != nil {
				logs.Error("发送消息失败：%v", err)
				return err
			}
			return nil
		}
	}
	return errors.New(fmt.Sprintf("路由 [ %v ] 不支持。", router))
}

func (e *EventHandler) KickHandler(packet *protocol.Packet, c *WsConnection) error {
	return nil
}

// 监听对端发送的消息 nats
func (e *EventHandler) remoteReadChanHandler() {
	for {
		select {
		case body, ok := <-e.RemoteReadChan:
			if ok {
				logs.Debug("收到 remote 消息：%v", body)
				msg := new(remote.Msg)
				if err := json.Unmarshal(body, msg); err != nil {
					logs.Error("解析数据异常：%v", err)
					continue
				}
				if msg.Type == remote.SessionType {
					e.SetSessionData(msg)
					continue
				}
				if msg.Body != nil {
					// 类型为 request 或 response，最终返回的都是 response
					if msg.Body.Type == protocol.Request || msg.Body.Type == protocol.Response {
						msg.Body.Type = protocol.Response
						e.Response(msg)
					}
					if msg.Body.Type == protocol.Push {
						e.RemotePushChan <- msg
					}
				}
			}
		}
	}
}

// 获取服务
func (e *EventHandler) selectDst(serverType string) (string, error) {
	serverConfigs, ok := game.Conf.ServersConf.TypeServer[serverType]
	if !ok {
		return "", errors.New(fmt.Sprintf("没有找到服务：%s", serverType))
	}
	// 随机获取一个服务
	rand.Seed(uint64(time.Now().UnixNano()))
	index := rand.Intn(len(serverConfigs))
	return serverConfigs[index].ID, nil
}

func (e *EventHandler) remotePushChanHandler() {
	for {
		select {
		case body, ok := <-e.RemotePushChan:
			if ok && body.Body.Type == protocol.Push {
				e.Response(body)
			}
		}
	}
}

func (e *EventHandler) Response(msg *remote.Msg) {
	connection, ok := e.wsClients[msg.Cid]
	if !ok {
		logs.Error("没有找到 WebSocket 客户端:%v", msg.Cid)
		return
	}
	buf, err := protocol.MessageEncode(msg.Body)
	if err != nil {
		logs.Error("编码异常:%v", err)
		return
	}
	encode, err := protocol.Encode(protocol.Data, buf)
	if err != nil {
		logs.Error("消息编码异常：%v", err)
		return
	}
	if msg.Body.Type == protocol.Push {
		for _, v := range e.wsClients {
			if ut.Contains(msg.PushUser, v.Session.Uid) {
				if err = v.SendMessage(encode); err != nil {
					logs.Error("消息发送异常：%v", err)
				}
			}
		}
		return
	}
	if err = connection.SendMessage(encode); err != nil {
		logs.Error("消息发送异常：%v", err)
	}
}

func (e *EventHandler) SetSessionData(msg *remote.Msg) {
	conn, ok := e.wsClients[msg.Cid]
	if ok {
		conn.Session.SetData(msg.Uid, msg.SessionData)
	}
}
